//-----------------------------------------------------------------------------
// Copyright SECOM Telecom Co., LTD
//
// Target:         uPD78F0485
// Tool chain:     NEC PM+ v6.30
// Author:		   Gan zhiyong
// Date:		   2011-5-8
// Vervion:	       V1.1
//-----------------------------------------------------------------------------

#include "stm32f4xx_hal.h"
#include "GP21.h"
#include "stdio.h"
#include "main.h"

unsigned long MS1022_Fire1Measure(unsigned char *pTimeoutFlag, unsigned char *pNoIntFlag);
void MS1022_Reset(void);
void SPI_Enable(void);
void SPI_Disable(void);
void SPI_SendZero(void);
void SPI_SendOne(void);
void SPI_WriteCommand(unsigned char wbuf8);
void SPI_WriteRegister(unsigned long wbuf32);
unsigned long SPI_ReadResult(unsigned char addr);
unsigned int SPI_ReadStatus(void);
unsigned char SPI_ReadTest(void);
uint32_t tdcCounter = 0;

//-----------------------------------------------------------------------------
// Local Macro definition
//-----------------------------------------------------------------------------
#define THREE_STOP_EN				// Caculate 3 stop hits


#define MS1022_SCK_L			HAL_GPIO_WritePin(TDC_SCK_GPIO_Port,TDC_SCK_Pin,GPIO_PIN_RESET)
#define MS1022_SCK_H			HAL_GPIO_WritePin(TDC_SCK_GPIO_Port,TDC_SCK_Pin,GPIO_PIN_SET)
#define MS1022_SI_L				HAL_GPIO_WritePin(TDC_SI_GPIO_Port,TDC_SI_Pin,GPIO_PIN_RESET)
#define MS1022_SI_H				HAL_GPIO_WritePin(TDC_SI_GPIO_Port,TDC_SI_Pin,GPIO_PIN_SET)
#define MS1022_SO				(TDC_SO_GPIO_Port->IDR & TDC_SO_Pin)
#define MS1022_INT			(TDC_INT_GPIO_Port->IDR & TDC_INT_Pin)
#define MS1022_SSN_L			HAL_GPIO_WritePin(TDC_CS_GPIO_Port,TDC_CS_Pin,GPIO_PIN_RESET)
#define MS1022_SSN_H			HAL_GPIO_WritePin(TDC_CS_GPIO_Port,TDC_CS_Pin,GPIO_PIN_SET)


#define COMMAND_INIT					0x70
#define COMMAND_PowerOnReset			0x50
#define COMMAND_StartTOF				0x01
#define COMMAND_StartTemp				0x02
#define COMMAND_StartCalResonator		0x03
#define COMMAND_StartTOFRestart			0x05
#define COMMAND_StartTempRestart		0x06

#define COMMAND_ReadReg0				0xB0
#define COMMAND_ReadReg1				0xB1
#define COMMAND_ReadReg2				0xB2
#define COMMAND_ReadReg3				0xB3
#define COMMAND_ReadStatus				0xB4
#define COMMAND_ReadTest				0xB5


//REG0: ANZ_FIRE D_FIRE z32 dhs S_CHS pt cle afk tclk cal ncal  mes2 neg
//      0000      0010   00 00   01    1  0  0    1    1   0    1    000
#define MS1022_REG0		0x80020668

//REG1: HIT2  HIT1 EFST N HITIN2 HN1 32k sf sel seltst
//        0010  0001  0   1 00 0   010  1  0  000  000
//        reg 1 >>  0010 0001 0100 0010 1000 0000   214280
#define MS1022_REG1	0x81214280


//    EN_INT EDG2 EDG1  
//001      0   0   000 0000 0000 0000 0000
// reg 2 >>  0010 0000 0000 0000 0000 0000
//8220 0000
#define MS1022_REG2		0x82200000

/*
EN_AUT EN_FS  EN_ERR SEL_MB2
 0       0      1     11     000 0000 0000 0000 0000
reg 3 >> 0011 1000 0000 0000 0000 0000
8338 0000
*/
#define MS1022_REG3		0x83380000

//REG4: delay3=0;
#define MS1022_REG4		0x84200000

//REG5: default
//#define MS1022_REG5_fire1	0x85400000

/*
EN_ANA  NEG_STOP N DA_KO N TW2 EN_INT START_CHS CYC_T CYC_TO HZ60 FIRE0_DEF QUAD_RES DB_RES te FIRE
  0        0     0  0000 0  00    1      0        00     00      0      0        1       0     0  000
reg 6 >> 0000 0000 0010  0000 0010 0000
*/
#define MS1022_REG6		0x86002020



//-----------------------------------------------------------------------------
// Module:   MS1022_Init
// Description: MS1022_Init
//-----------------------------------------------------------------------------
void MS1022_Init(void)
{
	MS1022_Reset();
	SPI_WriteCommand(COMMAND_PowerOnReset);
	SPI_WriteRegister(MS1022_REG0);
	SPI_WriteRegister(MS1022_REG1);
	SPI_WriteRegister(MS1022_REG2);
	SPI_WriteRegister(MS1022_REG3);
	SPI_WriteRegister(MS1022_REG4);
	SPI_WriteRegister(MS1022_REG6);
}


//-----------------------------------------------------------------------------
// Module:   MS1022_GetDeltaT
// Description: Complete once measurement including Downstream-time, 
//			    clock calibration, and upstream-time.
// return value: signed 32-bit value, high 16-bit are integer, low 16-bit are
//               fractional digits. To get the final value(unit: ns), this
//               return value must be divided by 65536, and multiplied by 250ns.
// return Parameter: *pValidFlag - Indicate whether the returned value is valid.
//-----------------------------------------------------------------------------
signed long MS1022_GetDeltaT(unsigned char *pValidFlag)
{
	return 0;
}


//-----------------------------------------------------------------------------
// Module:   MS1022_Fire1Measure
// Description: Fire1 transmit, fire2 receive
//-----------------------------------------------------------------------------
unsigned long MS1022_DoMeasure(unsigned char *pTimeoutFlag, unsigned char *pNoIntFlag)
{
	unsigned int	status;
	volatile uint64_t	cnt;
	unsigned long result = 0,tmp = 0;
	unsigned long ret = -(1<<30);
	*pTimeoutFlag = 0;
	*pNoIntFlag = 0;
	//SPI_WriteCommand(COMMAND_INIT);
	//SPI_WriteCommand(COMMAND_StartTOF);
	
	cnt = 10000000;		// if int signal has not occurred until 5ms, break.
	/*while(MS1022_INT)	// wait for low level on INT pin of MS1022
	{
		cnt--;
		if(cnt == 0)
		{
			*pNoIntFlag = 1;
			return(0);
		}
	}*/
	*pNoIntFlag = 0;
	
	status = SPI_ReadStatus();
	//printf("read status %d\n",status);
	if((status & 0x0600) == 0)	// timeout flags are 0
	{
		*pTimeoutFlag = 0;
		ret = (SPI_ReadResult(COMMAND_ReadReg0));
		//printf("%ld\n",result>>15);
		//tmp = result & 0x7FFF;
		//result = result>>15;
		//ret = result + tmp/32768.0;
		//printf("%lf\n",ret);
		return ret;
	}
	else	// timeout error process
	{
		*pTimeoutFlag = 1;
		return(ret);
	}
}

void MS1022_NewMeasure() {
	//printf("N\n");
	SPI_WriteCommand(COMMAND_INIT);
	tdcCounter = HAL_GetTick();
}


//-----------------------------------------------------------------------------
// Module:   MS1022_CalResonator
// Description: Calibrate 4MHz clock
//-----------------------------------------------------------------------------
unsigned long MS1022_CalResonator(unsigned char *pTimeoutFlag, unsigned char *pNoIntFlag)
{
	unsigned int	status;
	unsigned int	cnt;
	
	SPI_WriteCommand(COMMAND_INIT);
	SPI_WriteCommand(COMMAND_StartCalResonator);
	
	cnt = 1000;		// if int signal has not occurred until 5ms, break.
	while(MS1022_INT)	// wait for low level on INT pin of MS1022
	{
		cnt--;
		if(cnt == 0)
		{
			*pNoIntFlag = 1;
			return(0);
		}
	}
	*pNoIntFlag = 0;
	
	status = SPI_ReadStatus();
	if((status & 0x0600) == 0)	// timeout flags are 0
	{
		*pTimeoutFlag = 0;
		return(SPI_ReadResult(COMMAND_ReadReg0));
	}
	else	// timeout error process
	{
		*pTimeoutFlag = 1;
		return(0);
	}
}


//-----------------------------------------------------------------------------
// Module:   MS1022_Reset
// Description: Reset MS1022
//-----------------------------------------------------------------------------
void MS1022_Reset(void)
{

}


//-----------------------------------------------------------------------------
// Module:   SPI_Enable
// Description: SPI_Enable
//-----------------------------------------------------------------------------
void SPI_Enable(void)
{
	MS1022_SSN_L;	// followed by 40ns at least
	__nop();
	__nop();
}


//-----------------------------------------------------------------------------
// Module:   SPI_Disable
// Description: SPI_Disable
//-----------------------------------------------------------------------------
void SPI_Disable(void)
{
	__nop();			// 70ns at least
	MS1022_SSN_H;	// followed by 50ns at least
	__nop();
	__nop();
}


//-----------------------------------------------------------------------------
// Module:   SPI_SendZero
// Description: SPI_SendZero
//-----------------------------------------------------------------------------
void SPI_SendZero(void)
{
	MS1022_SCK_H;	// SCK high level 50ns at least
	__nop();
	MS1022_SI_L;
	__nop();
	MS1022_SCK_L;	// SCK low level 50ns at least
	__nop();
}


//-----------------------------------------------------------------------------
// Module:   SPI_SendOne
// Description: SPI_SendOne
//-----------------------------------------------------------------------------
void SPI_SendOne(void)
{
	MS1022_SCK_H;	// SCK high level 50ns at least
	__nop();
	MS1022_SI_H;
	__nop();
	MS1022_SCK_L;	// SCK low level 50ns at least
	__nop();
}


//-----------------------------------------------------------------------------
// Module:   SPI_WriteCommand
// Description: SPI_WriteCommand
//-----------------------------------------------------------------------------
void SPI_WriteCommand(unsigned char wbuf8)
{
	unsigned char cnt, tmp;
	
	tmp = 0x80;
 	SPI_Enable();
 	for(cnt=8; cnt>0; cnt--)
    {
    	if((wbuf8&tmp) == 0)
       		SPI_SendZero();
     	else
       		SPI_SendOne();
     	
     	tmp = tmp >> 1;
    }
    SPI_Disable();
}


//-----------------------------------------------------------------------------
// Module:   SPI_WriteRegister
// Description: SPI_WriteRegister
//-----------------------------------------------------------------------------
void SPI_WriteRegister(unsigned long wbuf32)
{
	unsigned char cnt;
 	unsigned long tmp;
 	
 	tmp = 0x80000000;
 	SPI_Enable();
 	for(cnt=32; cnt>0; cnt--)
    {
     	if((wbuf32&tmp) == 0)
       		SPI_SendZero();
     	else
       		SPI_SendOne();
     
     	tmp = tmp >> 1;
    }
    SPI_Disable();
}


//-----------------------------------------------------------------------------
// Module:   SPI_ReadResult
// Description: SPI_ReadResult
//-----------------------------------------------------------------------------
unsigned long SPI_ReadResult(unsigned char addr)
{
 	unsigned char cnt, tmp8;
 	unsigned long tmp32;
 	unsigned long rbuf32;
 	
 	tmp8 = 0x80;
 	SPI_Enable();
 	for(cnt=8; cnt>0; cnt--)
    {
    	if((addr&tmp8) == 0)
       		SPI_SendZero();
     	else
       		SPI_SendOne();
     	
     	tmp8 = tmp8 >> 1;
    }
    
    tmp32 = 0x80000000;
    rbuf32 = 0x00000000;
 	for(cnt=32; cnt>0; cnt--)
    {
    	MS1022_SCK_H;
     	__nop();
    	if(MS1022_SO)
        	rbuf32 |= tmp32;
     	tmp32 = tmp32 >> 1;
     	MS1022_SCK_L;
     	__nop();
    }
    SPI_Disable();
    
 	return(rbuf32);
}


//-----------------------------------------------------------------------------
// Module:   SPI_ReadStatus
// Description: SPI_ReadStatus
//-----------------------------------------------------------------------------
unsigned int SPI_ReadStatus(void)
{
 	unsigned char cnt, tmp8;
 	unsigned int  tmp16;
 	unsigned int  rbuf16;
 	
 	tmp8 = 0x80;
 	SPI_Enable();
 	for(cnt=8; cnt>0; cnt--)
    {
    	if((COMMAND_ReadStatus&tmp8) == 0)
       		SPI_SendZero();
     	else
       		SPI_SendOne();
     	
     	tmp8 = tmp8 >> 1;
    }
    
    tmp16 = 0x8000;
    rbuf16 = 0x0000;
 	for(cnt=16; cnt>0; cnt--)
    {
    	MS1022_SCK_H;
     	__nop();
    	if(MS1022_SO)
        	rbuf16 |= tmp16;
     	tmp16 = tmp16 >> 1;
     	MS1022_SCK_L;
     	__nop();
    }
    SPI_Disable();
    
 	return(rbuf16);
}


//-----------------------------------------------------------------------------
// Module:   SPI_ReadTest
// Description: This function is only for testing communication between MCU and MS1022.
//-----------------------------------------------------------------------------
unsigned char SPI_ReadTest(void)
{
 	unsigned char cnt, tmp8;
 	unsigned char rbuf8;
 	
 	tmp8 = 0x80;
 	SPI_Enable();
 	for(cnt=8; cnt>0; cnt--)
    {
    	if((COMMAND_ReadTest&tmp8) == 0)
       		SPI_SendZero();
     	else
       		SPI_SendOne();
     	
     	tmp8 = tmp8 >> 1;
    }
    
    tmp8 = 0x80;
    rbuf8 = 0x00;
 	for(cnt=8; cnt>0; cnt--)
    {
    	MS1022_SCK_H;
     	__nop();
    	if(MS1022_SO)
        	rbuf8 |= tmp8;
     	tmp8 = tmp8 >> 1;
     	MS1022_SCK_L;
     	__nop();
    }
    SPI_Disable();
    
 	return(rbuf8);
}

